#define UNUSED_VALUE 1


KEW_EXPORT_METHOD(kew_relation_factory_new)
{
    KewRelationObject *relation = kew_new_object(kew_relation_type, 0);
    KewRelationObject *inverse = kew_new_object(kew_relation_type, 0);
    
    relation->inverse = inverse;
    inverse->inverse = relation;
    
    results[0] = relation;
}
    
KEW_EXPORT_METHOD(kew_relation_inverse)
{
    results[0] = ((KewRelationObject *)receiver)->inverse;
}

inline static void set_relation(KewObject *source, KewRelationObject *relation, KewObject *dest)
{
    GHashTable *set = (GHashTable *) kew_object_get_extension(source, (gpointer) relation);
    if (! set) {
        set = g_hash_table_new(g_direct_hash, g_direct_equal);
        kew_object_add_extension(source, (gpointer) relation, (gpointer) set);
    }
    g_hash_table_insert(set, dest, (gpointer) UNUSED_VALUE);
}

KEW_EXPORT_METHOD(kew_relation_assert)
{
    set_relation(args[0], (KewRelationObject *) receiver, args[1]);
    set_relation(args[1], ((KewRelationObject *) receiver)->inverse, args[0]);
}

inline static void unset_relation(KewObject *source, KewRelationObject *relation, KewObject *dest)
{
    GHashTable *set = (GHashTable *) kew_object_get_extension(lhs, (gpointer) relation);
    if (! set)
        return;
    g_hash_table_remove(set, (gpointer) dest);
    if (g_hash_table_size(set) == 0) {
        g_hash_table_destroy(set);
        kew_object_remove_extension(source, (gpointer) relation);
    }
}

KEW_EXPORT_METHOD(kew_relation_unassert)
{
    unset_relation(args[0], (KewRelationObject *) receiver, args[1]);
    unset_relation(args[1], ((KewRelationObject *) receiver)->inverse, args[0]);
}

KEW_EXPORT_METHOD(kew_relation_read)
{
    GHashTable *set = (GHashTable *) kew_object_get_extension(lhs, (gpointer) relation);
    if (! set) {
        results[0] = kew_empty_set;
        return;
    }
    results[0] = kew_wrap_set(set);
}
